from EventController import EntityEvents

class NodeType:
    SEQUENTIAL, RANDOM, PRIORITY, INSTANT_CONDITION, CONDITION, INSTANT_ACTION, ACTION = range(7)

class NodeState:
    QUIT, START, SUCCESS, FAIL, ERROR, PROCESSING = range(6)

class BTNode:
    def __init__(self, key, type, nodeLength=0):
        self.type = type
        self.nodeLength = nodeLength
        self.processChildIdx = 0
        self.idx = 0
        self.key = key
    
    def __copy__(self):
        return BTNode(self.key, self.type, self.nodeLength)
        
    def _typeToStr(self):
        strtype = ''
        if self.type == NodeType.SEQUENTIAL:
            strtype = 'SEQUENTIAL'
        elif self.type == NodeType.RANDOM:
            strtype = 'RANDOM'
        elif self.type == NodeType.PRIORITY:
            strtype = 'PRIORITY'
        elif self.type == NodeType.CONDITION:
            strtype = 'CONDITION'
        elif self.type == NodeType.ACTION:
            strtype ='ACTION'
        return strtype;
    def __repr__(self):
        return "T"+self._typeToStr()+":N"+str(self.nodeLength)
    def __str__(self):
        

        return 'type: ' + self._typeToStr() + ' nodelength: ' + str(self.nodeLength)



def getFindThreatNode():
    
    findThreat = {'name': 'FindHighestThreat', 'type': NodeType.ACTION}
                  
    return findThreat

def consEnemyTree():
    root = {'name': 'EnemyTree', 'type': NodeType.SEQUENTIAL}
    
    attackChildren = [{'name': 'TargetExist', 'type': NodeType.CONDITION}
                      ,{'name': 'Attack', 'type': NodeType.ACTION}
                      ]
    attack = {'name': 'attackTree'
              ,'type': NodeType.SEQUENTIAL
              ,'children':attackChildren 
              }
    
    #find cover not implemented yet
    advance = {'name': 'Advance', 'type': NodeType.ACTION}
    
    root['children'] = [attack, advance]
    
    return root

def consEntityHealthPotionTree():
    """
    This is a tree for handling entity events
    """
    root = {'name': 'PotionTree', 'type': NodeType.SEQUENTIAL}
    
    chuckPotion = {'name': 'HealthPotion', 'type': NodeType.ACTION}
    root["children"] = [chuckPotion]
    return root

def consTreeA():
    #This function shall construct a bt tree.
    root = {'name' : 'treeA', 'type': NodeType.SEQUENTIAL}
    
    detectThenAttackSequenceChildren = [{'name': 'detectplayer1', 'type': NodeType.CONDITION},
                            {'name': 'saysomething', 'type': NodeType.ACTION}]
    detectThenAttackSequenceSelector = {'name': 'dtaseq1', 'type': NodeType.SEQUENTIAL, 'children': detectThenAttackSequenceChildren}
    
    followPathAction = {'name': 'followaction1', 'type': NodeType.ACTION}

    
    root['children'] = [detectThenAttackSequenceSelector, followPathAction]

    return root

def constPriorityTree(treeA):
    root = {'name': 'rootbehavior', 'type': NodeType.PRIORITY}

    randomYawns = [{'name': 'yawnA', 'type': NodeType.ACTION}
                   , {'name': 'yawnB', 'type': NodeType.ACTION}]
    randomAnims = [{'name': 'animA', 'type': NodeType.ACTION}
                   , {'name': 'animB', 'type': NodeType.ACTION}
                   , {'name': 'animC', 'type': NodeType.ACTION}]
    
    randomIdles = [{'name': 'yawn', 'type': NodeType.RANDOM, 'children': randomYawns}
                   , {'name': 'fart', 'type': NodeType.ACTION}
                   , {'name': 'idleAnims', 'type': NodeType.RANDOM, 'children': randomAnims}
                   ]
    root['children'] = [treeA, {'name': 'randomIdles', 'type': NodeType.RANDOM, 'children': randomIdles}] #the priority is explicit in the order of the list.

    return root

'''
\precondition root is not None and is a valid node type.
\post condition a list has be constructed using post-order traversal of a BT.
\invariance if a node has no children key, then it's a leaf node.
'''
def postOrderCons(node):
    #end condition
    count = 0
    list = []
    children = node.get('children', None)
    if children is not None:
        for i in range(0, len(children)):
            result = postOrderCons(children[i])
            for j in range(0, len(result[0])):
                list.append(result[0][j])
            count += result[1]
        #post-order handling current node.
        count += 1 #count self
        currentNode = BTNode(node['name'], node['type'], count) 
        list.insert(0, currentNode)
    else:
        count += 1
        currentNode = BTNode(node['name'], node['type'])
        list.append(currentNode)

    return [list, count]

def BTToList(root):
    result = postOrderCons(root)
    return result[0]

def BTEnemyList():
    root = consEnemyTree()
    return BTToList(root)

def BTEntityEventTreeLists():
    """
    This function returns a dict of trees for for handling specific events (usually for interrupts).
    """
    healthPotion = consEntityHealthPotionTree()
    eventDict = {EntityEvents.ON_CRITICAL_HEALTH: BTToList(healthPotion)}
    return eventDict
